package com.zoe.onelink.guide.loader.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ReUtil;
import com.vladsch.flexmark.html.AttributeProvider;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.html.IndependentAttributeProviderFactory;
import com.vladsch.flexmark.html.renderer.LinkResolverContext;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.parser.ParserEmulationProfile;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;
import com.zoe.onelink.guide.constant.OnelinkGuideConstant;
import com.zoe.onelink.guide.loader.OnelinkGuideLoader;
import com.zoe.onelink.guide.provider.attr.HtmlAttributeProvider;
import com.zoe.onelink.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.ResourceUtils;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2022</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2022-11-25
 */
@Slf4j
public class OnelinkApiExceptionGuideLoader implements OnelinkGuideLoader {

    private static final String ONELINK_GUIDE_DIR = "onelink/guides";

    @Override
    public Map<String, String> loadGuide() {
        List<String> contents;
        try {
            PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = pathMatchingResourcePatternResolver.getResources(ResourceUtils.CLASSPATH_URL_PREFIX + ONELINK_GUIDE_DIR + "/**.md");
            contents = Stream.of(resources)
                    .map(resource -> {
                        try {
                            log.info("[异常指南模块] 开始加载API异常指南文件: {}", resource.getFilename());
                            return IoUtil.readUtf8(resource.getInputStream());
                        } catch (IOException e) {
                            log.warn("[异常指南模块] 开始加载API异常指南文件: {}", resource.getFilename());
                            return null;
                        }
                    }).filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList());
        } catch (IOException e) {
            log.warn("[异常指南模块] 加载异常指南文件信息失败:{}", e.getMessage());
            contents = Collections.emptyList();
        }
        if (contents.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<String, String> guideMap = new HashMap<>(contents.size());
        for (String content : contents) {
            try {
                Map<String, String> subGuideMap = resolveContent(content);
                guideMap.putAll(subGuideMap);
            } catch (Exception e) {
                log.warn("[异常指南模块] 解析异常指南文件信息失败:{}", e.getMessage());
            }
        }
        return guideMap;
    }

    @NotNull
    private static Map<String, String> resolveContent(String content) {
        if (StrUtil.isBlank(content)) {
            return Collections.emptyMap();
        }

        List<String> guideIds = ReUtil.findAllGroup1(OnelinkGuideConstant.SPIT_PATTERN_STR, content)
                .stream()
                .map(guideId -> guideId.replace(" ", ""))
                .collect(Collectors.toList());

        List<String> guideContents = Stream.of(content.split(OnelinkGuideConstant.SPIT_PATTERN_STR))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());

        if (guideIds.size() != guideContents.size()) {
            log.warn("[异常指南模块] 指南ID和指南内容数量不匹配");
            return Collections.emptyMap();
        }

        // 先只支持 Markdown 转 HTML
        MutableDataSet options = new MutableDataSet();
        options.setFrom(ParserEmulationProfile.MARKDOWN);
        Parser parser = Parser.builder(options).build();
        HtmlRenderer renderer = HtmlRenderer.builder(options)
                .attributeProviderFactory(new IndependentAttributeProviderFactory() {
                    @Override
                    public @NotNull AttributeProvider apply(@NotNull LinkResolverContext linkResolverContext) {
                        return new HtmlAttributeProvider();
                    }
                }).build();

        List<String> htmlContents = guideContents.stream()
                .map(guideContent -> {
                    Node document = parser.parse(guideContent);
                    return renderer.render(document);
                }).collect(Collectors.toList());

        Map<String, String> guideMap = new HashMap<>(guideIds.size());
        for (int i = 0; i < guideIds.size(); i++) {
            guideMap.put(guideIds.get(i), htmlContents.get(i));
        }
        return guideMap;
    }

}
